from typing import List
import shortuuid
import json
import logging
from common import Result


LOGGER = logging.getLogger(__name__)


class OutlineKit:
    def __init__(self, outline: dict, level: int = 0) -> None:
        self.id = outline["id"] if "id" in outline else shortuuid.uuid()
        self.title = outline["title"] if "title" in outline else "未填写段标题"
        self.text = outline["text"] if "text" in outline else ""
        self.level = level
        self.subNode: List[OutlineKit] = []
        self.subNodeIdMap = {}
        self.parentNode: OutlineKit = None
        if "subtitle" in outline:
            for item in outline["subtitle"]:
                newNode = OutlineKit(item, self.level + 1)
                self._lowLevelAddNewChild(newNode)

    def __repr__(self) -> str:
        return json.dumps(
            {
                "id": self.id,
                "level": self.level,
                "title": self.title,
                "subLength": len(self.subNode),
                "childList": list(self.subNodeIdMap.keys()),
            },
            ensure_ascii=False,
        )

    def deletePara(self, paraId) -> Result:
        try:
            node = self.findNodeByParaId(paraId)
            if node is None:
                LOGGER.error(f"node not found {paraId}")
                return Result().error("node not found")

            parentNode: OutlineKit = node.parentNode
            if parentNode is None:
                LOGGER.error(f"parentNode not found {paraId}")
                return Result().error("parentNode not found")

            del parentNode.subNodeIdMap[paraId]

            _allParaIdList = []
            for n in parentNode.subNode:
                _allParaIdList.append(n.id)
            nodeIndex = _allParaIdList.index(paraId)
            del parentNode.subNode[nodeIndex]
            return Result()
        except Exception as e:
            LOGGER.exception(e)
            return Result().error(str(e))

    def movePara(self, moveType, paraId) -> Result:
        node = self.findNodeByParaId(paraId)
        if node is None:
            LOGGER.error(f"node not found {paraId}")
            return Result().error("node not found")
        parentNode = node.parentNode
        if parentNode is None:
            LOGGER.error(f"parentNode not found {paraId}")
            return Result().error("parentNode not found")

        paraIdList = []
        for n in parentNode.subNode:
            paraIdList.append(n.id)

        srcIndex = paraIdList.index(paraId)
        if srcIndex < 0:
            return Result().error("同级节点中未找到")

        if moveType == "up":
            if srcIndex == 0:
                return Result().error("已到顶")
            dstIndex = srcIndex - 1
        else:
            if srcIndex == (len(parentNode.subNode) - 1):
                return Result().error("已到底")
            dstIndex = srcIndex + 1

        tmp = parentNode.subNode[dstIndex]
        parentNode.subNode[dstIndex] = parentNode.subNode[srcIndex]
        parentNode.subNode[srcIndex] = tmp

        return Result(message="排序完成")

    def _lowLevelAddNewChild(self, node: "OutlineKit", afterThisParaId: str = ""):
        node.parentNode = self
        node.level = self.level + 1
        self.subNodeIdMap[node.id] = node

        if afterThisParaId is None or afterThisParaId not in self.subNodeIdMap:
            self.subNode.append(node)
            return

        # 否则，查找位置，插入指定位置

        _allParaIdList = []
        for n in self.subNode:
            _allParaIdList.append(n.id)

        afterThisIndex = _allParaIdList.index(afterThisParaId)
        self.subNode.insert(afterThisIndex + 1, node)

    def findNodeByParaId(self, paraId) -> "OutlineKit":
        if self.id == paraId:
            return self

        for sn in self.subNode:
            r = sn.findNodeByParaId(paraId)
            if r is not None:
                return r
        return None

    def getAllChildrenId(self):
        allIds = list(self.subNodeIdMap.keys())
        for node in self.subNode:
            allIds.extend(node.getAllChildrenId())
        return allIds

    def dumpsToDict(self):
        subNode = []
        for n in self.subNode:
            subNode.append(n.dumpsToDict())

        return {
            "id": self.id,
            "title": self.title,
            "text": self.text,
            "subtitle": subNode,
        }

    def debugPrint(self):
        print("\t" * self.level + f"{self}")
        for n in self.subNode:
            n.debugPrint()

    def addParaAfter(self, paraId: str, title: str, text: str = ""):
        """ "插入某个para之后，就要找到他的父节点，找到对应的子节点位置，"""
        baseNode: "OutlineKit" = self.findNodeByParaId(paraId)
        if baseNode is None:
            return Result().error("basePara not found")
        if baseNode.parentNode is None:
            return Result().error("basePara's parentNode not found")

        newNode = OutlineKit(
            {
                "id": shortuuid.uuid(),
                "title": title,
                "text": text,
            }
        )
        LOGGER.error(baseNode.parentNode.title)
        baseNode.parentNode._lowLevelAddNewChild(node=newNode, afterThisParaId=paraId)

        return Result().setData(newNode.id)

    def addChildPara(self, baseParaId: str, title: str, text: str = "") -> Result:
        """成为这个节点的子节点，"""
        baseNode: "OutlineKit" = self.findNodeByParaId(baseParaId)
        if baseNode is None:
            return Result().error("basePara not found")

        newNode = OutlineKit(
            {
                "id": shortuuid.uuid(),
                "title": title,
                "text": text,
            }
        )
        LOGGER.error(baseNode.title)
        baseNode._lowLevelAddNewChild(newNode)

        return Result().setData(newNode.id)

    @staticmethod
    def restoreFromDict(outlineDict: dict):
        return OutlineKit(outlineDict)
